package it.blueocean.acanto.taglibrary.jsp.taglib.tags.dataset;

import it.blueocean.acanto.taglibrary.jsp.taglib.tags.dataset.filter.DatasetFilter;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;

import javax.inject.Named;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;

@Named("hibernateDataset")
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class HibernateDataset extends DataSetStateBean
{
	private static final long serialVersionUID = 987465418354856L;

	private final static Logger logger_ = LoggerFactory.getLogger(HibernateDataset.class);

	@PersistenceContext(type = PersistenceContextType.EXTENDED)
	private EntityManager entityManager;

	public HibernateDataset()
	{
	}

	protected QueryExecutionResult executeQuery(int i, int j) throws NamingException
	{
		String s = getCompleteQuery();

		Query query = entityManager.createQuery(s);

		if(logger_.isDebugEnabled())
			logger_.debug((new StringBuilder()).append("Complete query: ").append(s).toString());

		setParameters(query);
		int k;
		Object aobj[];
		if(j > 0)
		{
			if(getQuery().indexOf(" group by ") > 0)
			{
				k = query.getResultList().size();
			}
			else
			{
				String s1 = getFilteredQuery();

				if(!s.startsWith("from "))
					s1 = s1.substring(s1.indexOf(" from "));

				Query query1 = entityManager.createQuery((new StringBuilder()).append("select count(*) ").append(s1)
						.toString());

				setParameters(query1);

				Long long1 = Long.valueOf(((Long) query1.getSingleResult()).longValue());
				k = long1.intValue();
			}
			query.setFirstResult(i);
			query.setMaxResults(j);
			aobj = query.getResultList().toArray();
		}
		else
		{
			aobj = query.getResultList().toArray();
			k = aobj.length;
		}
		String as[] = null;
		if(k > 0)
			as = getColumns(aobj[0]);
		return new QueryExecutionResult(as, aobj, k);
	}

	private void setParameters(Query query)
	{
		Iterator<Object> iterator = getParams().iterator();
		
		int i;
		
		for (i = 1; iterator.hasNext(); i++)
		{
			Object obj = iterator.next();
			
			logger_.debug((new StringBuilder())
					.append("setting param ").append(i).append(": '").append(obj)
					.append("' type : ").append(obj.getClass().getName())
					.toString());
			
			query.setParameter(i, obj);
		}

		DatasetFilter datasetfilter = getDatasetFilter();
		
		if(datasetfilter != null && datasetfilter.getFilterString().length() > 0)
		{
			for (Iterator<?> iterator1 = datasetfilter.getFilterParams().iterator(); iterator1.hasNext();)
			{
				Object obj1 = iterator1.next();
				
				if(logger_.isDebugEnabled())
				{
					logger_.debug((new StringBuilder())
							.append("setting filter param ").append(i).append(": '")
							.append(obj1).append("' type : ").append(obj1.getClass().getName())
							.toString());
				}
				if(obj1 instanceof String)
				{
					logger_.debug((new StringBuilder())
							.append("---> filter param ").append(i).append(": '")
							.append(obj1).append("' is a String ")
							.toString());
				}
				
				query.setParameter(i, obj1);
			}
		}
	}

	public String getCompleteQuery()
	{
		String str = getFilteredQuery();
		OrderByClause localOrderByClause = getOrderByClause();
		if(localOrderByClause != null)
			str = str + " order by " + localOrderByClause;
		return str;
	}

	public String getFilteredQuery()
	{
		String str = getQuery();
		DatasetFilter localDatasetFilter = getDatasetFilter();
		if((localDatasetFilter != null) && (localDatasetFilter.getFilterString().length() > 0))
			str = str + " where " + localDatasetFilter.getFilterString();
		return str;
	}

	protected String[] getColumns(Object obj)
	{
		ArrayList<String> arraylist = new ArrayList<String>();
		Method amethod[] = obj.getClass().getMethods();
		for (int i = 0; i < amethod.length; i++)
		{
			if(amethod[i].getName().startsWith("get") && !amethod[i].getName().equals("getClass")
					&& amethod[i].getParameterTypes().length == 0)
			{
				String s = (new StringBuilder()).append(Character.toLowerCase(amethod[i].getName().charAt(3)))
						.append(amethod[i].getName().substring(4)).toString();
				arraylist.add(s);
			}
			if(amethod[i].getName().startsWith("is") && amethod[i].getParameterTypes().length == 0)
			{
				String s1 = (new StringBuilder()).append(Character.toLowerCase(amethod[i].getName().charAt(2)))
						.append(amethod[i].getName().substring(3)).toString();
				arraylist.add(s1);
			}
		}

		String as[] = new String[arraylist.size()];
		for (int j = 0; j < arraylist.size(); j++)
			as[j] = (String) arraylist.get(j);
		return as;
	}

}